﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TemplateWizard;
using DatabaseToCode;
using DatabaseToCode.ExtensionMethods;
using TemplatePackage.MvcTemplate;
using System.IO;
using TemplatePackage.MvcTemplate.Views;

namespace MVCTemplateWizard
{
    public class MvcWizard : IWizard
    {
        private InputInformations viewModel;
        private Dictionary<string, string> parameters;
        private EnvDTE.DTE dte;

        /// <summary>
        /// Runs custom wizard logic before opening an item in the template.
        /// </summary>
        /// <param name="projectItem">The project item that will be opened.</param>
        public void BeforeOpeningFile(EnvDTE.ProjectItem projectItem)
        {
        }

        /// <summary>
        /// Runs custom wizard logic when a project has finished generating.
        /// </summary>
        /// <param name="project">The project that finished generating.</param>
        public void ProjectFinishedGenerating(EnvDTE.Project project)
        {
            var databaseAnalyser = new DatabaseAnalyser(viewModel.ProviderName, viewModel.ConnectionString);
            var schema = databaseAnalyser.Analyse();
            schema.Name = viewModel.ContextName;

            foreach (var table in schema.Tables) //.Where(t => !t.Value.PrimaryKeyName.Contains(',')))
            {
                #region Création et ajout du model
                // Création et ajout du model
                var modelTemplate = new ModelTemplate();
                modelTemplate.Session = new Dictionary<string, object>();
                modelTemplate.Session.Add("Table", table.Value);
                modelTemplate.Session.Add("Namespace", viewModel.Namespace);
                modelTemplate.Session.Add("Schema", schema);
                modelTemplate.Initialize();

                WriteFileToProject(project,
                    Path.Combine(parameters["$destinationdirectory$"], "Models"),
                    table.Value.ClassName.Singuliarize() + "Model.cs",
                    modelTemplate.TransformText());
                #endregion

                #region Création et ajout du Controller
                // Création et ajout du controller
                var controllerTemplate = new ControllerTemplate();
                controllerTemplate.Session = new Dictionary<string, object>();
                controllerTemplate.Session.Add("Table", table.Value);
                controllerTemplate.Session.Add("Schema", schema);
                controllerTemplate.Session.Add("Context", viewModel.ContextName);
                controllerTemplate.Session.Add("Namespace", viewModel.Namespace);
                controllerTemplate.Initialize();

                WriteFileToProject(project, 
                    Path.Combine(parameters["$destinationdirectory$"], "Controllers"), 
                    table.Value.ClassName.Plurialize() + "Controller.cs",
                    controllerTemplate.TransformText());
                #endregion

                #region Views
                #region Create
                var createTemplate = new CreateTemplate();
                createTemplate.Session = new Dictionary<string, object>();
                createTemplate.Session.Add("Namespace", viewModel.Namespace);
                createTemplate.Session.Add("Table", table.Value);
                createTemplate.Initialize();

                WriteFileToProject(project,
                    Path.Combine(parameters["$destinationdirectory$"], "Views", table.Value.ClassName.Plurialize()),
                    "Create.cshtml", //table.Value.ClassName.Plurialize() + "Controller.cs",
                    createTemplate.TransformText());
                #endregion

                #region Delete
                var deleteTemplate = new DeleteTemplate();
                deleteTemplate.Session = new Dictionary<string, object>();
                deleteTemplate.Session.Add("Namespace", viewModel.Namespace);
                deleteTemplate.Session.Add("Table", table.Value);
                deleteTemplate.Initialize();

                WriteFileToProject(project,
                    Path.Combine(parameters["$destinationdirectory$"], "Views", table.Value.ClassName.Plurialize()),
                    "Delete.cshtml", //table.Value.ClassName.Plurialize() + "Controller.cs",
                    deleteTemplate.TransformText());
                #endregion

                #region Index
                var indexTemplate = new IndexTemplate();
                indexTemplate.Session = new Dictionary<string, object>();
                indexTemplate.Session.Add("Namespace", viewModel.Namespace);
                indexTemplate.Session.Add("Table", table.Value);
                indexTemplate.Initialize();

                WriteFileToProject(project,
                    Path.Combine(parameters["$destinationdirectory$"], "Views", table.Value.ClassName.Plurialize()),
                    "Index.cshtml", //table.Value.ClassName.Plurialize() + "Controller.cs",
                    indexTemplate.TransformText());

                var gridTemplate = new _GridTemplate();
                gridTemplate.Session = new Dictionary<string, object>();
                gridTemplate.Session.Add("Namespace", viewModel.Namespace);
                gridTemplate.Session.Add("Table", table.Value);
                gridTemplate.Initialize();

                WriteFileToProject(project,
                    Path.Combine(parameters["$destinationdirectory$"], "Views", table.Value.ClassName.Plurialize()),
                    "_Grid.cshtml", //table.Value.ClassName.Plurialize() + "Controller.cs",
                    gridTemplate.TransformText());


                #endregion

                #region Edit
                var editTemplate = new EditTemplate();
                editTemplate.Session = new Dictionary<string, object>();
                editTemplate.Session.Add("Namespace", viewModel.Namespace);
                editTemplate.Session.Add("Table", table.Value);
                editTemplate.Initialize();

                WriteFileToProject(project,
                    Path.Combine(parameters["$destinationdirectory$"], "Views", table.Value.ClassName.Plurialize()),
                    "Edit.cshtml", //table.Value.ClassName.Plurialize() + "Controller.cs",
                    editTemplate.TransformText());
                #endregion

                #region Details
                var detailsTemplate = new DetailsTemplate();
                detailsTemplate.Session = new Dictionary<string, object>();
                detailsTemplate.Session.Add("Namespace", viewModel.Namespace);
                detailsTemplate.Session.Add("Table", table.Value);
                detailsTemplate.Initialize();

                WriteFileToProject(project,
                    Path.Combine(parameters["$destinationdirectory$"], "Views", table.Value.ClassName.Plurialize()),
                    "Details.cshtml", //table.Value.ClassName.Plurialize() + "Controller.cs",
                    detailsTemplate.TransformText());

                var detailTemplate = new _DetailsTemplate();
                detailTemplate.Session = new Dictionary<string, object>();
                detailTemplate.Session.Add("Namespace", viewModel.Namespace);
                detailTemplate.Session.Add("Table", table.Value);
                detailTemplate.Initialize();

                WriteFileToProject(project,
                    Path.Combine(parameters["$destinationdirectory$"], "Views", table.Value.ClassName.Plurialize()),
                    "_Details.cshtml", //table.Value.ClassName.Plurialize() + "Controller.cs",
                    detailTemplate.TransformText());

                #endregion

                #region _CreateOrEdit
                var createOrEditTemplate = new _CreateOrEditTemplate();
                createOrEditTemplate.Session = new Dictionary<string, object>();
                createOrEditTemplate.Session.Add("Namespace", viewModel.Namespace);
                createOrEditTemplate.Session.Add("Table", table.Value);
                createOrEditTemplate.Initialize();

                WriteFileToProject(project,
                    Path.Combine(parameters["$destinationdirectory$"], "Views", table.Value.ClassName.Plurialize()),
                    "_CreateOrEdit.cshtml", //table.Value.ClassName.Plurialize() + "Controller.cs",
                    createOrEditTemplate.TransformText());
                #endregion
                #endregion

            }

            // Création et ajout du DbContext
            var contextTemplate = new DataContextTemplate();
            contextTemplate.Session = new Dictionary<string, object>();
            //contextTemplate.Session.Add("Table", table.Value);
            contextTemplate.Session.Add("Namespace", viewModel.Namespace);
            contextTemplate.Session.Add("Schema", schema);
            contextTemplate.Session.Add("Context", viewModel.ContextName);
            contextTemplate.Initialize();
            var result2 = contextTemplate.TransformText();

            File.WriteAllText(
                Path.Combine(parameters["$destinationdirectory$"],
                    "Models",
                    viewModel.ContextName + ".cs"),
                result2);

            project.ProjectItems.AddFromFile(Path.Combine(parameters["$destinationdirectory$"],
                    "Models",
                    viewModel.ContextName + ".cs"));

        }

        /// <summary>
        /// Writes the file to project.
        /// </summary>
        /// <param name="project">The project.</param>
        /// <param name="folder">The folder.</param>
        /// <param name="filename">The filename.</param>
        /// <param name="result">The result.</param>
        private void WriteFileToProject(
            EnvDTE.Project project, 
            string folder,
            string filename,
            string result)
        {
            Directory.CreateDirectory(folder);
            File.WriteAllText(Path.Combine(folder, filename), result);
            project.ProjectItems.AddFromFile(Path.Combine(folder, filename));
        }

        /// <summary>
        /// Runs custom wizard logic when a project item has finished generating.
        /// </summary>
        /// <param name="projectItem">The project item that finished generating.</param>
        public void ProjectItemFinishedGenerating(EnvDTE.ProjectItem projectItem)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Runs custom wizard logic when the wizard has completed all tasks.
        /// </summary>
        public void RunFinished()
        {

        }

        /// <summary>
        /// Runs custom wizard logic at the beginning of a template wizard run.
        /// </summary>
        /// <param name="automationObject">The automation object being used by the template wizard.</param>
        /// <param name="replacementsDictionary">The list of standard parameters to be replaced.</param>
        /// <param name="runKind">A <see cref="T:Microsoft.VisualStudio.TemplateWizard.WizardRunKind"/> indicating the type of wizard run.</param>
        /// <param name="customParams">The custom parameters with which to perform parameter replacement in the project.</param>
        public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
        {
            this.dte = automationObject as EnvDTE.DTE;
            viewModel = new InputInformations();
            var view = new ProjectInformationView(viewModel, null);

            viewModel.Namespace = replacementsDictionary["$projectname$"];
            viewModel.ContextName = replacementsDictionary["$projectname$"] + "Context";

            view.ShowDialog();

            replacementsDictionary.Add("$providerName$", viewModel.ProviderName);
            replacementsDictionary.Add("$connectionStringName$", viewModel.ContextName);
            replacementsDictionary.Add("$connectionString$", viewModel.ConnectionString);

            parameters = new Dictionary<string, string>();
            replacementsDictionary.ToList().ForEach(elem => parameters.Add(elem.Key, elem.Value));

        }

        /// <summary>
        /// Indicates whether the specified project item should be added to the project.
        /// </summary>
        /// <param name="filePath">The path to the project item.</param>
        /// <returns>
        /// true if the project item should be added to the project; otherwise, false.
        /// </returns>
        public bool ShouldAddProjectItem(string filePath)
        {
            return true;
        }
    }
}
